import uuid

import requests
from ajson import aj
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status
from rest_framework.decorators import api_view
from django.core.cache import cache
from rest_framework.views import APIView

from config import OutTime
from suishoubang.settings import WX_APP_ID, WX_APP_SECRET
from utils import others, AliyunUtil
from utils.Rsa import MD5, hide_phone
from utils.network import Result, is_login, CustomGenericViewSet
from utils.redis_util import KEY_PREFIX
from .models import User, Province, City
from .serializers import UserSerializer, UserInvitationSerializer, ProvinceSerializer, ProvinceJoinSerializer


@swagger_auto_schema(
    methods=['POST'],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['account', 'password'],
        properties={
            'account': openapi.Schema(type=openapi.TYPE_STRING, description="账户名，可以是手机号和邮箱"),
            'password': openapi.Schema(type=openapi.TYPE_STRING, description="密码"),
        },
        responses={
            403: "账号或密码错误",
            200: "成功"
        })
)
@api_view(['POST'])
def LoginView(requests):
    """登录接口

    使用手机号或者邮箱登录

    会返回一个uuid提供查询token的信息

    然后把这个token放在请求头

    名字叫 Authorization

    大小写严格区分
    """
    data = requests.data
    user_item = User.objects.filter(phone=data['account'], password=MD5.encryption(data['password']))
    user_item = user_item \
        if len(user_item) != 0 else \
        User.objects.filter(email=data['account'], password=data['password'])

    if len(user_item) == 0:
        return Result.error(code=status.HTTP_400_BAD_REQUEST, message="登陆失败,账号或密码错误")
    serializer = UserSerializer(user_item.first())

    ret_data = serializer.data

    # 设置redis的键
    redis_key = KEY_PREFIX['login'](ret_data['phone'], ret_data['email'])
    # 设置缓存为60天
    cache.set(redis_key, ret_data, OutTime.TOKEN_OUT_TIME)
    print(redis_key)

    return Result.success(token=redis_key, user_id=ret_data['id'])


class UserInfoView(CustomGenericViewSet):
    @is_login(key='user_obj')
    def post(self, requests, user_obj):
        """
        通过请求头token获取用户信息
        """
        # 删除密码
        if 'invitation' in requests.data.keys() and requests.data.get("invitation"):
            serializer = UserInvitationSerializer(user_obj)
        else:
            serializer = UserSerializer(user_obj)
        ret = serializer.data
        # ret['phone'] = hide_phone(ret['phone'])
        return Result.success(data=ret)

    @is_login(key='user_obj')
    def update_nickname(self, requests, user_obj: User):
        user_obj.name = requests.data.get('name')
        user_obj.save()
        serializer = UserSerializer(user_obj)
        ret = serializer.data
        # ret['phone'] = hide_phone(ret['phone'])
        return Result.success(data=ret)


@swagger_auto_schema(
    methods=['POST'],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['phone', 'password'],
        properties={
            'name': openapi.Schema(type=openapi.TYPE_INTEGER, default='suishoubang-' + str(uuid.uuid4()),
                                   description="昵称"),
            'phone': openapi.Schema(type=openapi.TYPE_INTEGER, description="手机号"),
            'password': openapi.Schema(type=openapi.TYPE_STRING, description="密码"),
            'email': openapi.Schema(type=openapi.TYPE_STRING, description="邮箱"),
            'sex': openapi.Schema(type=openapi.TYPE_INTEGER, description="性别"),
            'birthday': openapi.Schema(type=openapi.TYPE_STRING, description="出生日期"),
            'sms': openapi.Schema(type=openapi.TYPE_STRING, description="注册手机验证码"),
        },
    )
)
@api_view(['POST'])
def CreateView(requests):
    """
    注册账号

    手机号码和密码为必填

    其他的默认:

        email:null

        sex:0

        birthday:2001-01-01


    """
    data = requests.data

    if not others.verify_mobile(data['phone']):
        return Result.error(code=status.HTTP_400_BAD_REQUEST, message="手机号码输入错误")

    user_item = User.objects.filter(phone=data['phone'])
    if len(user_item) > 0:
        return Result.error(code=status.HTTP_400_BAD_REQUEST, message="手机号已被注册")
    # 注册存入redis的键
    sign_key = KEY_PREFIX['sign'](data['phone'])
    # 如果已经发送了注册验证码
    if cache.has_key(sign_key):
        if data['sms']:
            if data['sms'] == cache.get(sign_key):
                # 注册账号
                if len(str(data['password'])) < 6:
                    return Result.error(code=status.HTTP_400_BAD_REQUEST, message="密码长度为6到30位字符")
                # 加密密码
                data['password'] = MD5.encryption(str(data['password']))
                serializer = UserSerializer(data=data)
                serializer.is_valid(raise_exception=True)
                serializer.save()
                # 删除验证码
                cache.delete_pattern(sign_key)
                return Result.success(message="注册成功")
            else:
                return Result.error(code=status.HTTP_400_BAD_REQUEST, message="验证码错误")
        else:
            return Result.error(code=status.HTTP_400_BAD_REQUEST, message="验证码不允许为空")
    else:
        # 发送验证码
        code = others.get_ver_code(sign_key)
        sms_response = AliyunUtil.send_sms_code(phone=data['phone'], code=code)
        ret = aj.load(str(sms_response, encoding="utf-8"))
        if ret['Code'] == 'OK':
            return Result.success(message="验证码发送成功")
        else:
            return Result.error(error=ret)


@swagger_auto_schema(
    methods=['POST'],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['phone'],
        properties={
            'phone': openapi.Schema(type=openapi.TYPE_INTEGER, description="手机号"),
            'password': openapi.Schema(type=openapi.TYPE_STRING, description="新密码"),
            'sms': openapi.Schema(type=openapi.TYPE_STRING, description="手机验证码"),
        },
    )
)
@api_view(['POST'])
def ResetView(requests):
    """发送短信"""
    data = requests.data
    phone = data['phone']
    # 先查找是否存在使用这个手机的用户
    user_phone = User.objects.filter(phone=phone)
    if len(user_phone) == 0:
        return Result.error(code=status.HTTP_400_BAD_REQUEST, message="用户不存在")
    # 得到键
    reset_key = KEY_PREFIX['reset'](phone)

    if cache.has_key(reset_key):
        if data['sms']:
            if data['sms'] == cache.get(reset_key):
                # 注册账号
                if len(str(data['password'])) < 6:
                    return Result.error(code=status.HTTP_400_BAD_REQUEST, message="密码长度为6到30位字符")
                # 加密密码
                user_item = User.objects.filter(phone=phone).first()
                user_item.password = MD5.encryption(str(data['password']))
                user_item.update()
                # 删除验证码
                cache.delete_pattern(reset_key)
                return Result.success(message="重置密码成功")
            else:
                return Result.error(code=status.HTTP_400_BAD_REQUEST, message="验证码错误")
        else:
            return Result.error(code=status.HTTP_400_BAD_REQUEST, message="验证码不允许为空")
    else:
        # 获取重置密码的验证码
        code = others.get_reset_code(reset_key)
        sms_response = AliyunUtil.send_sms_code(phone=data['phone'], code=code)
        ret = aj.load(str(sms_response, encoding="utf-8"))
        if 'Code' in ret.keys():
            return Result.success(message="验证码发送成功")
        else:
            return Result.error(error=ret)


@api_view(['POST'])
@is_login(header_token=True)
def exitLoginView(requests, token):
    cache.delete_pattern(token)
    return Result.success(exit_status=not cache.has_key(token))


class RegionView(CustomGenericViewSet):

    def province(self, requests):
        serializer = ProvinceSerializer(Province.objects.all(), many=True)
        return Result.success(data=serializer.data)

    def city(self, requests):
        data = requests.data
        pro = Province.objects.filter(pk=data['pid'])
        serializer = ProvinceJoinSerializer(instance=pro, many=True)
        return Result.success(data=serializer.data)

    def district(self, requests):
        pass


class WxLogin(APIView):
    def post(self, request):
        ret = requests.get('https://api.weixin.qq.com/sns/jscode2session?'
                           'appid=%s&secret=%s&js_code=%s&grant_type=authorization_code' % (
                               WX_APP_ID, WX_APP_SECRET, request.data.get('code')))
        ret = aj.load(ret.text)
        return Result.success(data=ret)
